package com.company;

import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.net.Socket;
import java.util.*;
import java.util.List;


public class GobangGame extends JFrame {
    private String playerWorB = "黑子";
    private String gameName;
    private int ROWS = 15; // 棋盘行数
    private int COLS = 15; // 棋盘列数
    private  int CELL_SIZE = 40; // 每个格子的大小
    private  int BOARD_SIZE = CELL_SIZE * ROWS; // 棋盘大小
    private int[][] board = new int[ROWS][COLS]; // 存储棋盘状态
    private boolean gameOver = false; // 游戏结束标志
    private JLabel statusLabel;

    private JButton undoButton;
    private GameClient client;
    private BufferedReader in; // 添加这行
    private Map<Point, Integer> pointToPlayerMap = new HashMap<>();

    // 现有的成员变量
    private int currentPlayer = 1; // 当前客户端玩家编号
    private int activePlayer = 1;  // 当前回合的玩家编号

    private static List<MoveRecord> moveRecords = new ArrayList<>();
    private static int currentTurn = 0;

    public class GameClient {
        private Socket socket;
        private PrintWriter out;


        public GameClient(String serverAddress, int serverPort) throws IOException {
            socket = new Socket(serverAddress, serverPort);
            out = new PrintWriter(socket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            new Thread(this::run).start();
        }

        private void run() {
            try {
                String serverMessage;
                while ((serverMessage = in.readLine()) != null) {
                    System.out.println("Received from server: " + serverMessage);
                    handleServerResponse(serverMessage); // 处理服务器响应
                }
            } catch (IOException e) {
                System.out.println("Connection to server lost.");
                e.printStackTrace();
            } finally {
                // 安全关闭资源
                closeResources();
            }
        }

        private void closeResources() {
            try {
                if (socket != null) socket.close();
                if (in != null) in.close();
                if (out != null) out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        public void sendMessage(String message) {
            out.println(message);
        }
    }

    private void handleServerResponse(String serverMessage) {
        try {
            String[] parts = serverMessage.split(",");
            System.out.println(Arrays.toString(parts));
            if ("role".equals(parts[0])) {
                System.out.println("已经执行"+parts[1]);
                // 角色分配逻辑
                if (parts[1].equals("black"))
                {
                    playerWorB = "黑子";
                    setTitle("五子棋游戏-季姬击鸡记"+"    "+"玩家: "+gameName+"  "+playerWorB);
                    currentPlayer = 1;
                }else{
                    playerWorB = "白子";
                    setTitle("五子棋游戏-季姬击鸡记"+"    "+"玩家: "+gameName+"  "+playerWorB);
                    currentPlayer = 2;
                }
                SwingUtilities.invokeLater(this::updateStatus);
            } else if ("undo".equals(parts[0])) {

                    // 服务器发送的悔棋数据更新
                    StringBuffer stringBuffer = new StringBuffer();
                    for (int i = 1; i < parts.length; i++) {
                        stringBuffer.append(parts[i]+":");
                    }
                    String s = stringBuffer.toString();
                    updateLocalMoveRecords(s); // 实现服务器发送的格式解析
                    SwingUtilities.invokeLater(this::repaintBoard);
                    SwingUtilities.invokeLater(this::updateStatus);

            } else if ("currentPlayer".equals(parts[0])) {
                // 处理回合信息
                activePlayer = Integer.parseInt(parts[1]);
                SwingUtilities.invokeLater(this::updateStatus);
            } else if ("move".equals(parts[0])){
                // 处理常规游戏更新
                // 处理常规游戏更新
                // 处理落子信息
                int player = Integer.parseInt(parts[1]);
                int row = Integer.parseInt(parts[2]);
                int col = Integer.parseInt(parts[3]);
                // 添加到历史记录
                moveRecords.add(new MoveRecord(player, new Point(row, col), currentTurn));
                currentTurn++;
                // 更新棋盘显示
                SwingUtilities.invokeLater(this::repaintBoard);
                // 更新状态显示
                SwingUtilities.invokeLater(this::updateStatus);

            }else if("isundo".equals(parts[0]))
            {
                String undoPlayer = parts[1];
                String currentPlayer = playerWorB.equals("黑子")?"1":"2";
                if (currentPlayer.equals(undoPlayer))
                {
                    if ("noUndo".equals(parts[2]))
                    {
                        JOptionPane.showMessageDialog(GobangGame.this,"对方不同意悔棋");
                    }
                }else if(!currentPlayer.equals(undoPlayer)&&parts[2].equals("0")){
                    int userOption =  JOptionPane.showConfirmDialog(GobangGame.this,"是否要同意悔棋","提示",JOptionPane.OK_OPTION,JOptionPane.QUESTION_MESSAGE);
                    if (userOption == JOptionPane.OK_OPTION) {
                        undoMove();
                    }else {
                        client.sendMessage(parts[0]+","+parts[1]+","+"noUndo");
                    }
                }
            }else if("gameOver".equals(parts[0]))
            {
                playMusic("src/com/company/win.wav");
                ImageIcon icon = new ImageIcon("src/com/company/win.jpg");	//注意设置图片尺寸，50*50px较适合
                JOptionPane.showMessageDialog(GobangGame.this, icon,parts[1] , JOptionPane.WARNING_MESSAGE);
                this.setVisible(false); // 隐藏或关闭当前窗口
                this.dispose();
                SwingUtilities.invokeLater(() -> {
                    new starGame().setVisible(true);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("接收到的数据格式不正确或不完整: " + serverMessage);
        }
    }

    private void updateLocalMoveRecords(String moveRecordDatas) {

        String moveRecordData = moveRecordDatas.substring(1,moveRecordDatas.length()-2);

        // 清空本地记录
        moveRecords.clear();

        String[] moves = moveRecordData.split(";");
        // System.out.println(Arrays.toString(moves)+"你好");
        for (String moveStr : moves) {
            if (!moveStr.isEmpty()) {  // 检查字符串是否为空
                String[] moveParts = moveStr.split(":");
                int player = Integer.parseInt(moveParts[0]);
                int row = Integer.parseInt(moveParts[1]);
                int col = Integer.parseInt(moveParts[2]);
                int turn = Integer.parseInt(moveParts[3]);
                moveRecords.add(new MoveRecord(player, new Point(row, col), turn));
            }
        }
        System.out.println(moveRecords.size()+"haha");
        repaintBoard();
        currentTurn = moveRecords.size() + 1;
    }



    private void repaintBoard() {
        // 清除棋盘上的所有棋子
        for (int i = 0; i < ROWS; i++) {
            for (int j = 0; j < COLS; j++) {
                board[i][j] = 0;
            }
        }

        // 根据 moveRecords 中的记录重新绘制棋盘
        for (MoveRecord record : moveRecords) {
            int player = record.player;
            Point move = record.move;
            board[move.x][move.y] = player;
        }

        // 使用 Graphics 对象重新绘制棋盘和棋子
        // 这通常会在 JPanel 的 paintComponent 方法中进行
        repaint();
    }




    private void updateStatus() {
        if (activePlayer == 1) {
            statusLabel.setText("黑方回合");
        } else if (activePlayer == 2) {
            statusLabel.setText("白方回合");
        }
        // 如果有其他状态更新，也可以在这里添加
    }

    private  static String ip;

    int BOARD_PADDING_TOP = 400; // 举例，像素值



    public GobangGame(String ip, String gameName,int rowS,int cloS,String port) {

        this.ROWS=rowS;
        this.COLS=cloS;
        this.board=new int[rowS][cloS];
        BOARD_SIZE = CELL_SIZE * ROWS; // 棋盘大小

        // playBackgroundMusic("src/com/company/bgm.wav");
        try {
            client = new GameClient(ip, Integer.parseInt(port));
            // 使用 client.sendMessage 发送数据
        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "无法连接到服务器", "连接错误", JOptionPane.ERROR_MESSAGE);
        }


        this.gameName = gameName;
        setTitle("五子棋游戏-季姬击鸡记"+"    "+"玩家: "+gameName+"  "+playerWorB);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 创建主面板，并使用边界布局
        JPanel mainPanel = new JPanel(new BorderLayout());
        add(mainPanel);

        // 初始化棋盘面板，并设置背景图
        JPanel boardPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                // 设置背景图
                Image bgImage = new ImageIcon("src/com/company/bg.jpg").getImage();
                if(playerWorB.equals("白子"))
                {
                    bgImage = new ImageIcon("src/com/company/bgw.jpg").getImage();
                }


                g.drawImage(bgImage, 0, 0, getWidth(), getHeight(), this);
                // 绘制棋盘的逻辑

            }
        };


        boardPanel.setPreferredSize(new Dimension(BOARD_SIZE, BOARD_SIZE));
        boardPanel.setBorder(new EmptyBorder(30, 0, 0, 0)); // 上边距设置为10像素

        mainPanel.add(boardPanel, BorderLayout.CENTER);

      // 初始化状态标签并添加到南部区域
        statusLabel = new JLabel("玩家 1 的回合", SwingConstants.CENTER);
        mainPanel.add(statusLabel, BorderLayout.SOUTH);

       // 初始化悔棋按钮和南部面板
        undoButton = new JButton("悔棋");
        undoButton.addActionListener(e ->isundo()); // 确保 undoMove 方法存在

        JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        southPanel.add(undoButton);
        southPanel.add(statusLabel);
        mainPanel.add(southPanel, BorderLayout.SOUTH); // 这将添加到布局的南部区域

        pack();
        setLocationRelativeTo(null); // 设置窗口居中显示

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {

                super.mouseClicked(e);

                int offset = 30; // 与drawBoard中使用的偏移量相同
                if (gameOver || currentPlayer != activePlayer) {
                    return;
                }
                int row = (e.getY() - offset) / CELL_SIZE;
                int col = e.getX() / CELL_SIZE;
                if (row >= 0 && row < ROWS && col >= 0 && col < COLS && board[row][col] == 0) {
                    board[row][col] = currentPlayer;
                    playMusic("src/com/company/click.wav");
                    repaint();

                    // 发送落子信息到服务器
                    String message = "move"+","+currentPlayer + "," + row + "," + col ;
                    client.sendMessage(message);

                    // 检查游戏是否结束
                    if (checkWinner(row, col)) {
                        String game = currentPlayer==1?"黑子":"白子";
                        String winmes = "玩家"+gameName+" "+game+"胜利!";
                        client.sendMessage("gameOver,"+winmes);
                       //该消息框的提示图标会被自定义的图标覆盖掉
                        gameOver = true;
                    } else {
                        // 切换到下一个玩家
                        activePlayer = currentPlayer == 1 ? 2 : 1;
                        updateStatus();
                    }
                }else{
                    JOptionPane.showMessageDialog(GobangGame.this,"已经有棋子");
                }
            }
        });



   }

   private  void isundo()
   {
       playMusic("src/com/company/huiqi.wav");
       if(moveRecords.size()==0)
       {
           JOptionPane.showMessageDialog(GobangGame.this,"不能在悔棋，你想干嘛");
       }else{
           if (activePlayer==1&&"黑子".equals(playerWorB)) {
               String undoPlayer = Integer.toString(activePlayer);
               String message ="isundo,"+undoPlayer+",0";
               client.sendMessage(message);
           }else if(activePlayer==2&&"白子".equals(playerWorB)){
               String undoPlayer = Integer.toString(activePlayer);
               String message ="isundo,"+undoPlayer+",0";
               client.sendMessage(message);
           }else {
               JOptionPane.showMessageDialog(GobangGame.this,"不是你的回合不能悔棋");
           }
       }

   }

    private void undoMove() {

        if (!moveRecords.isEmpty()) {
            // 从 moveRecords 获取最后一次移动的回合数
            int lastTurn = moveRecords.get(moveRecords.size() - 1).turn;
            // 发送悔棋请求到服务器
            String message = "undo," + lastTurn;
            client.sendMessage(message);
        }

    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        drawBoard(g);
        drawPieces(g);
    }

    private void drawBoard(Graphics g) {
        int offset = 30; // 你希望线条下移的像素数
        for (int i = 0; i < ROWS; i++) {
            g.drawLine(CELL_SIZE / 2, CELL_SIZE / 2 + i * CELL_SIZE + offset,
                    BOARD_SIZE - CELL_SIZE / 2, CELL_SIZE / 2 + i * CELL_SIZE + offset);
            g.drawLine(CELL_SIZE / 2 + i * CELL_SIZE, CELL_SIZE / 2 + offset,
                    CELL_SIZE / 2 + i * CELL_SIZE, BOARD_SIZE - CELL_SIZE / 2 + offset);
        }
    }

    private void drawPieces(Graphics g) {
        int pieceDiameter = CELL_SIZE / 2; // 棋子直径为单元格的一半
        int offset = 30; // 同线条绘制时的偏移量
        for (int i = 0; i < ROWS; i++) {
            for (int j = 0; j < COLS; j++) {
                if (board[i][j] != 0) {
                    int x = j * CELL_SIZE + CELL_SIZE / 4;
                    int y = i * CELL_SIZE + CELL_SIZE / 4 + offset; // 加入偏移量
                    if (board[i][j] == 1) {
                        g.setColor(Color.BLACK); // 玩家1的棋子颜色
                    } else {
                        g.setColor(Color.WHITE); // 玩家2的棋子颜色
                    }
                    g.fillOval(x, y, pieceDiameter, pieceDiameter); // 绘制棋子
                }
            }
        }
    }

    // 检查是否有五个连续的棋子
    private boolean checkWinner(int row, int col) {
        return checkLine(row, col, 1, 0)  // 水平方向
                || checkLine(row, col, 0, 1)  // 垂直方向
                || checkLine(row, col, 1, 1)  // 对角线方向
                || checkLine(row, col, 1, -1); // 反对角线方向
    }

    // 检查特定方向上是否有五个连续的棋子
    private boolean checkLine(int row, int col, int dRow, int dCol) {
        int count = 1;
        // 向一个方向检查
        for (int i = 1; i < 5; i++) {
            if (row + i * dRow < ROWS && row + i * dRow >= 0
                    && col + i * dCol < COLS && col + i * dCol >= 0
                    && board[row + i * dRow][col + i * dCol] == currentPlayer) {
                count++;
            } else {
                break;
            }
        }
        // 向相反方向检查
        for (int i = 1; i < 5; i++) {
            if (row - i * dRow < ROWS && row - i * dRow >= 0
                    && col - i * dCol < COLS && col - i * dCol >= 0
                    && board[row - i * dRow][col - i * dCol] == currentPlayer) {
                count++;
            } else {
                break;
            }
        }
        return count >= 5;
    }

    public void playMusic(String musicPath) {
        try {
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(musicPath));
            Clip clip = AudioSystem.getClip();
            clip.open(audioInputStream);
            clip.start();
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            GobangGame game = new GobangGame("127.0.0.1","测试",20,20,"5000");
            game.setVisible(true);
        });
    }



}